package com.upstairstechnology.oi.determination;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

/**
 * Default implementation of command reader. This class handles reading the next
 * line of output from command execution, including error processing with
 * user-capable hook for additional error processing (see {@link #errorHandler}
 * and {@link #setErrorHandler(CommandReaderErrorHandler)}.
 * 
 * @author Jeff Jensen
 */
public class CommandReaderDefault implements CommandReader {
    /** Logger instance. */
    private static final Logger LOGGER =
            LoggerFactory.getLogger(CommandReaderDefault.class);

    /**
     * Called after logging all stdin and errin information from command
     * results, to enable additional processing by specific implementations.
     */
    private CommandReaderErrorHandler errorHandler;

    /**
     * {@inheritDoc}
     * 
     * This implementation, when inErr has message(s), logs all inErr and inStd
     * messages and then calls the {@link #errorHandler}.
     */
    public String readNextLine(List<String> command, BufferedReader inStd,
            BufferedReader inErr) throws IOException {
        String lineErr = inErr.readLine();
        String lineStd = inStd.readLine();

        if (lineErr != null) {
            LOGGER.error("Error running command: {}", command);
            LOGGER.error("    Reported Errors:");
            while (lineErr != null) {
                LOGGER.error("        {}", lineErr);
                lineErr = inErr.readLine();
            }

            LOGGER.error("    Command Output:");
            while (lineStd != null) {
                LOGGER.error("        {}", lineStd);
                lineStd = inStd.readLine();
            }

            errorHandler.handle(command);
        }

        return lineStd;
    }

    /**
     * {@inheritDoc}
     * 
     * This implementation simply wraps the input stream in a reader and then a
     * buffered reader.
     */
    public BufferedReader setupIn(InputStream is) {
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        return br;
    }

    /**
     * {@inheritDoc}
     */
    public CommandReaderErrorHandler getErrorHandler() {
        return errorHandler;
    }

    /**
     * {@inheritDoc}
     */
    @Required
    public void setErrorHandler(CommandReaderErrorHandler handler) {
        this.errorHandler = handler;
    }
}
